# uncompyle6 version 3.2.3
# Python bytecode 3.6 (3379)
# Decompiled from: Python 3.6.8 |Anaconda custom (64-bit)| (default, Feb 21 2019, 18:30:04) [MSC v.1916 64 bit (AMD64)]
# Embedded file name: server\routers\api\__init__.py
__author__ = "sanyi"
import json, logging
from werkzeug.wrappers import Request
from api import undefined
from server.http_responses.base import BaseResponse
from server.http_responses.http_errors import (
    RouteNotFound,
    BadApiRequest,
    ClassNotFound,
    MethodNotFound,
)
from server.http_responses.http_status_codes import Http200
from server.routers import Router
from server.routers.api.routes import Routes

logger = logging.getLogger("swagger.api.router")


class ApiRequest(Request):
    max_content_length = 10485760
    max_form_memory_size = 10485760


class ApiRouter(Router):
    RESPONSE_TYPE = "json"

    def __init__(
        self,
        swagger_document,
        handler_classes,
        check_routes=True,
        filter_on_host=True,
        filter_on_schema=True,
        extra_args=None,
        auth_factory=None,
    ):
        self.auth_factory = auth_factory
        if filter_on_host:
            host = swagger_document["host"]
        else:
            host = None
        if filter_on_schema:
            schemes = swagger_document["schemes"]
        else:
            schemes = None
        base_path = swagger_document["basePath"]
        super().__init__(base_path=base_path, host=host, methods=None, schemes=schemes)
        self._routes = Routes(swagger_document)
        self._handler_classes = handler_classes
        self._len_base_path = len(base_path)
        self.extra_args = extra_args
        if check_routes:
            self._routes.check_routes(self._handler_classes)

    def add_route(
        self,
        method,
        path,
        handler_class,
        handler_method,
        regex,
        request,
        security=None,
        response_validator=None,
    ):
        self._routes.add_route(
            method,
            path,
            handler_class,
            handler_method,
            regex,
            request,
            security,
            response_validator,
        )

    def handle_request(self, method, scheme, path, environment, start_response):
        content_type = environment.get("CONTENT_TYPE", None)
        if content_type:
            if not (
                content_type.lower().startswith("application/json")
                or content_type.lower().startswith("application/octet-stream")
            ):
                raise RouteNotFound()
        path = path[self._len_base_path :]
        for route_path, route_data in self._routes.routes[method].items():
            match = route_data["regex"].fullmatch(path)
            if match:
                try:
                    handler_class = self._handler_classes[route_data["handler_class"]]
                except KeyError:
                    raise ClassNotFound(route_data["handler_class"]) from None

                handler_method = getattr(
                    handler_class, route_data["handler_method"], None
                )
                if handler_method is None:
                    raise MethodNotFound(
                        "%s:%s"
                        % (route_data["handler_class"], route_data["handler_method"])
                    )
                request = ApiRequest(environment)
                remote_address = environment.get(
                    "HTTP_X_REAL_IP",
                    environment.get("HTTP_X_FORWARDED_FOR", environment["REMOTE_ADDR"]),
                )
                security = route_data.get("security", None)
                if security:
                    if not security[0]["type"] == "apiKey":
                        raise AssertionError
                    if not security[0]["name"] == "X-Auth":
                        raise AssertionError
                    if not security[0]["in"] == "header":
                        raise AssertionError
                    request_auth = self.auth_factory.get(request)
                else:
                    request_auth = None
                collected_validation_errors = {}
                collected_parameters = {}
                for parameter_name, parameter_descriptor in route_data[
                    "request"
                ].items():
                    ignore_required = False
                    add_defaults = True
                    accept_null_objects = False
                    parameter_source = parameter_descriptor["in"]
                    if parameter_source == "path":
                        try:
                            parameter_value = match.group(parameter_name)
                        except IndexError:
                            parameter_value = undefined

                    else:
                        if parameter_source == "query":
                            parameter_value = request.args.get(
                                parameter_name, undefined
                            )
                        else:
                            if parameter_source == "header":
                                parameter_value = request.headers.get(
                                    parameter_name, undefined
                                )
                            else:
                                if parameter_source == "body":
                                    parameter_value = undefined
                                    try:
                                        if "application/json" in content_type:
                                            accept_null_objects = True
                                            if method == "patch":
                                                add_defaults = False
                                                ignore_required = True
                                            try:
                                                parameter_value = json.loads(
                                                    request.data.decode("utf-8")
                                                )
                                            except ValueError:
                                                pass

                                        else:
                                            if (
                                                "application/octet-stream"
                                                in content_type
                                            ):
                                                accept_null_objects = False
                                                parameter_value = request.stream
                                    except TypeError:
                                        pass

                                else:
                                    raise NotImplementedError()
                                parameter_value = self._routes.validate_parameter(
                                    method,
                                    route_path,
                                    parameter_name,
                                    parameter_value,
                                    collected_validation_errors,
                                    ignore_required,
                                    add_defaults,
                                    accept_null_objects,
                                )
                                if collected_validation_errors:
                                    collected_parameters.clear()
                                else:
                                    if parameter_value != undefined:
                                        collected_parameters[
                                            parameter_name
                                        ] = parameter_value

                if collected_validation_errors:
                    logger.debug(collected_validation_errors)
                    raise BadApiRequest(
                        message="Validation errors",
                        details=[collected_validation_errors],
                    )
                logger.debug("params: %s", collected_parameters)
                extra_args = self.extra_args if self.extra_args else {}
                collected_parameters.update(extra_args)
                api_response = getattr(
                    handler_class(
                        request_auth=request_auth,
                        base_path=self.base_path,
                        remote_address=remote_address,
                        **collected_parameters
                    ),
                    route_data["handler_method"],
                )(**collected_parameters)
                if isinstance(api_response, BaseResponse):
                    start_response(api_response.response_status, api_response.headers)
                    yield from api_response()
                else:
                    api_response = Http200(api_response)
                    start_response(api_response.response_status, api_response.headers)
                    yield from api_response()
                return
        else:
            raise RouteNotFound()
